package com.divemotor.ventarepuestosinternet.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.primefaces.model.SortOrder;
import org.springframework.stereotype.Repository;

import com.divemotor.ventarepuestosinternet.beans.adapter.RepuestoAdapter;
import com.divemotor.ventarepuestosinternet.beans.form.RepuestoForm;
import com.divemotor.ventarepuestosinternet.dao.RepuestoDAO;
import com.divemotor.ventarepuestosinternet.model.Imagen;
import com.divemotor.ventarepuestosinternet.model.ImagenRepuesto;
import com.divemotor.ventarepuestosinternet.model.Promocion;
import com.divemotor.ventarepuestosinternet.model.PromocionRepuesto;
import com.divemotor.ventarepuestosinternet.model.Repuesto;
import com.divemotor.ventarepuestosinternet.util.Constantes;


@SuppressWarnings("unchecked")
@Repository(value="repuestoDAO")
public class RepuestoDAOImpl extends GenericoDAOImpl<Repuesto, Integer> implements RepuestoDAO,Serializable {

	private static final long serialVersionUID = 3816665150990364653L;

	public RepuestoDAOImpl(){
		setClase(Repuesto.class);
	}
	
	private void construirRestriccionRepuestos(RepuestoForm repuesto, Criteria criteria){
		
		String porc   = Constantes.PORCENTAJE;
		String codigo = repuesto.getCodigo();
		
		if (StringUtils.isNotBlank(codigo)) {
			criteria.add(Restrictions.like("codigo",porc+repuesto.getCodigo()+porc).ignoreCase());
		}

		String nombre = repuesto.getNombre();
		
		if (StringUtils.isNotBlank(nombre)) {
			criteria.add(Restrictions.like("nombre",porc + nombre + porc).ignoreCase());
		}

		String estado = repuesto.getEstado();
		
		if (StringUtils.isNotBlank(estado) && !estado.equals(Constantes.STR_NO_SELECCIONADO)) {
			criteria.add(Restrictions.eq("estado", repuesto.getEstado()));
		} else {
			criteria.add(Restrictions.not(Restrictions.eq("estado", Constantes.ESTADO_ELIMINADO)));
		}
	}
	
	@Override
	public List<Repuesto> buscarRepuestos(RepuestoForm repuesto){
		
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Repuesto.class);
		construirRestriccionRepuestos(repuesto, criteria);

		return criteria.list();
	}
	
	private void construirProyeccionRepuestos(Criteria criteria){
		ProjectionList lista = Projections.projectionList();
		lista.add(Projections.property("idRepuesto"), "idRepuesto")
			 .add(Projections.property("codigo"), "codigo")
		     .add(Projections.property("nombre"), "nombre")
		     .add(Projections.property("estado"), "estado");
		criteria.setProjection(lista);
	}

	@Override
	public List<RepuestoAdapter> buscarRepuestos(int inicio, int numeroResultadosPorPagina, SortOrder orden, 
										  		 String columnaOrden, RepuestoForm repuesto) {
		
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Repuesto.class, "repuesto");

		construirProyeccionRepuestos(criteria);
		construirRestriccionRepuestos(repuesto, criteria);
		
		//TODO MODIFICAR IGUAL QUE EL DE COTIZACION VERIFICAR LA PAGINACION DIFERENTE DE NULL
		criteria.setFirstResult(inicio);
		criteria.setMaxResults(numeroResultadosPorPagina);
		
		if (!(columnaOrden == null)) {
			if (orden.toString().equals(Constantes.ORDEN_ASCENDENTE_PRIMEFACES)) {
				criteria.addOrder(Order.asc(columnaOrden.toString()));
			} else {
				criteria.addOrder(Order.desc(columnaOrden.toString()));
			}
		}else{
			criteria.addOrder(Order.asc("nombre"));			
		}
		
		criteria.setResultTransformer(Transformers.aliasToBean(RepuestoAdapter.class));
		
		return criteria.list();
	}

	@Override
	public Integer obtenerNumeroRepuestosBusqueda(RepuestoForm repuesto) {
		
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Repuesto.class);
		criteria.setProjection(Projections.count("idRepuesto"));
		construirRestriccionRepuestos(repuesto, criteria);
		
		Number result = (Number) criteria.uniqueResult();
		return new Integer(result.intValue());
	}
	
	private void construirRestriccionRepuestosAsignablesPorImagen(Repuesto repuesto, Imagen imagen, Criteria criteria) {
		
		String porc   = Constantes.PORCENTAJE;
		
		Criteria criteriaIdsRepuestosNoAsignables = sessionFactory.getCurrentSession().createCriteria(ImagenRepuesto.class, "imagenRepuesto")
				.createAlias("imagenRepuesto.imagen", "imagen")
				.createAlias("imagenRepuesto.repuesto", "repuesto")
				.setProjection(Projections.projectionList().add(Projections.distinct(Projections.property("repuesto.idRepuesto"))))
				.add(Restrictions.eq("imagen.idImagen", imagen.getIdImagen()))
				.add(Restrictions.not(Restrictions.eq("imagenRepuesto.estado", Constantes.ESTADO_ELIMINADO)));
		
		List<Integer> listaIdsRepuestosNoAsignables = criteriaIdsRepuestosNoAsignables.list();
		
		if (listaIdsRepuestosNoAsignables != null && listaIdsRepuestosNoAsignables.size() > 0) {
			criteria.add(Restrictions.not(Restrictions.in("idRepuesto", listaIdsRepuestosNoAsignables)));
		}
		
		if (repuesto.getCodigo() != null && !repuesto.getCodigo().equals("")) {
			criteria.add(Restrictions.like("codigo",porc+repuesto.getCodigo()+porc).ignoreCase());
		}

		if (repuesto.getNombre() != null && !repuesto.getNombre().equals("")) {
			criteria.add(Restrictions.like("nombre",porc+repuesto.getNombre()+porc).ignoreCase());
		}

		criteria.add(Restrictions.eq("estado", Constantes.ESTADO_ACTIVO));
	}
	
	@Override
	public List<Repuesto> buscarRepuestosAsignablesPorImagen(int inicio, int numeroResultadosPorPagina,
			SortOrder orden, String columnaOrden, Repuesto repuesto, Imagen imagen) {
				
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Repuesto.class);
		criteria.setProjection(Projections.distinct(Projections
				.projectionList()
				.add(Projections.property("idRepuesto"), "idRepuesto")
				.add(Projections.property("codigo"), "codigo")
				.add(Projections.property("nombre"), "nombre")
				.add(Projections.property("estado"), "estado")
				.add(Projections.property("unidadMedida"), "unidadMedida")
		));
		
		construirRestriccionRepuestosAsignablesPorImagen(repuesto, imagen, criteria);
		
		criteria.setFirstResult(inicio);
		criteria.setMaxResults(numeroResultadosPorPagina);
		
		if (!(columnaOrden == null)) {
			if (orden.toString().equals(Constantes.ORDEN_ASCENDENTE_PRIMEFACES)) {
				criteria.addOrder(Order.asc(columnaOrden));
			} else {
				criteria.addOrder(Order.desc(columnaOrden));
			}
		}
		criteria.setResultTransformer(Transformers.aliasToBean(Repuesto.class));
		
		return criteria.list();
	}
	
	@Override
	public Integer obtenerNumeroRepuestosAsignablesPorImagen(Repuesto repuesto, Imagen imagen) {
		
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Repuesto.class).setProjection(Projections.count("idRepuesto"));
		construirRestriccionRepuestosAsignablesPorImagen(repuesto, imagen, criteria);
		
		Number result = (Number) criteria.uniqueResult();
		
		return new Integer(result.intValue());
	}
	
	private void construirRestriccionRepuestosAsignablesPorPromocion(Repuesto repuesto, Promocion promocion, Criteria criteriaIdsRepuestosNoAsignables,
																	 Criteria criteria){
		
		String porc   = Constantes.PORCENTAJE;
		List<Integer> listaIdsRepuestosNoAsignables = criteriaIdsRepuestosNoAsignables.list();
		
		if (listaIdsRepuestosNoAsignables != null && listaIdsRepuestosNoAsignables.size() > 0) {
			criteria.add(Restrictions.not(Restrictions.in("idRepuesto", listaIdsRepuestosNoAsignables)));
		}
		
		if (repuesto.getCodigo() != null && !repuesto.getCodigo().equals("")) {
			criteria.add(Restrictions.like("codigo",porc + repuesto.getCodigo() + porc).ignoreCase());
		}

		if (repuesto.getNombre() != null && !repuesto.getNombre().equals("")) {
			criteria.add(Restrictions.like("nombre",porc + repuesto.getNombre() + porc).ignoreCase());
		}

		criteria.add(Restrictions.eq("estado", Constantes.ESTADO_ACTIVO));
	}

	@Override
	public List<Repuesto> buscarRepuestosAsignablesPorPromocion(int inicio, int numeroResultadosPorPagina, 
			SortOrder orden, String columnaOrden, Repuesto repuesto, Promocion promocion) {
		
		Criteria criteriaIdsRepuestosNoAsignables = sessionFactory.getCurrentSession().createCriteria(PromocionRepuesto.class, "promocionRepuesto")
				.createAlias("promocionRepuesto.promocion", "promocion")
				.createAlias("promocionRepuesto.repuesto", "repuesto")
				.setProjection(Projections.projectionList().add(Projections.distinct(Projections.property("repuesto.idRepuesto"))))
				.add(Restrictions.eq("promocion.idPromocion", promocion.getIdPromocion()));
				
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Repuesto.class);
		criteria.setProjection(Projections.distinct(Projections
				.projectionList()
				.add(Projections.property("idRepuesto"), "idRepuesto")
				.add(Projections.property("codigo"), "codigo")
				.add(Projections.property("nombre"), "nombre")
				.add(Projections.property("codigo"), "codigo")
				.add(Projections.property("estado"), "estado")
				.add(Projections.property("unidadMedida"), "unidadMedida")
		));
		
		construirRestriccionRepuestosAsignablesPorPromocion(repuesto, promocion, criteriaIdsRepuestosNoAsignables, criteria);
		
		criteria.setFirstResult(inicio);
		criteria.setMaxResults(numeroResultadosPorPagina);
		
		if (!(columnaOrden == null)) {
			if (orden.toString().equals(Constantes.ORDEN_ASCENDENTE_PRIMEFACES)) {
				criteria.addOrder(Order.asc(columnaOrden.toString()));
			} else {
				criteria.addOrder(Order.desc(columnaOrden.toString()));
			}
		}
		criteria.setResultTransformer(Transformers.aliasToBean(Repuesto.class));
		return criteria.list();
	}
	
	@Override
	public Integer obtenerNumeroRepuestosAsignablesPorPromocion(Repuesto repuesto, Promocion promocion) {
		
		Criteria criteriaIdsRepuestosNoAsignables = sessionFactory.getCurrentSession().createCriteria(PromocionRepuesto.class, "promocionRepuesto")
				.createAlias("promocionRepuesto.promocion", "promocion")
				.createAlias("promocionRepuesto.repuesto", "repuesto")
				.setProjection(Projections.projectionList().add(Projections.distinct(Projections.property("repuesto.idRepuesto"))))
				.add(Restrictions.eq("promocion.idPromocion", promocion.getIdPromocion()));
				
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Repuesto.class).setProjection(Projections.count("idRepuesto"));
		
		construirRestriccionRepuestosAsignablesPorPromocion(repuesto, promocion, criteriaIdsRepuestosNoAsignables, criteria);
		
		Number result = (Number) criteria.uniqueResult();
		
		return new Integer(result.intValue());
	}

}
